<!DOCTYPE html>
<html lang="zh"
>
<head>
    <title>Python量化交易平台开发教程系列5-底层接口对接 - vn.py</title>
    <!-- Using the latest rendering mode for IE -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">


    <link href="/images/favicon.png" rel="icon">

<link rel="canonical" href="/basic-tutorial-5.html">

        <meta name="author" content="用Python的交易员" />
        <meta name="description" content="原创文章，转载请注明出处：用Python的交易员 前言 从本篇教程开始，所有的开发都会在Python环境中进行（谢天谢地可以和C++说再见了）。 通常情况下，一个交易程序的架构会由以下三个部分组成： 底层接口：负责对接行情和交易API，将数据推送到系统核心中，以及发送指令（下单、数据请求等） 中层引擎：用于整合程序中的各个组件（包括底层接口、数据库接口等等）到一个对象中，便于顶层UI调用 顶层GUI：用于显示数据和调用中层引擎暴露的主动函数，实现各项具体功能 上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构： 两边的Adapters代表的是底层接口（左边数据，右边交易） 红色圆柱形中包括的是中层引擎架构，事件驱动方面使用了Esper复杂事件处理（CEP）引擎，同时内置了一些常用的功能引擎，如期权定价引擎、外汇对冲模块、投资组合管理模块等 上方的Strategy1、2等代表的是顶层应用（算法策略、GUI界面等），通过调用中层引擎的功能来实现用户所需的业务 vn.py和AlgoTrader的比较： 这里对两个项目做一个简单的比较。 vn.py优势： 语言易用：Java语言比Python啰嗦 架构简洁 ..." />

        <meta property="og:site_name" content="vn.py" />
        <meta property="og:type" content="article"/>
        <meta property="og:title" content="Python量化交易平台开发教程系列5-底层接口对接"/>
        <meta property="og:url" content="/basic-tutorial-5.html"/>
        <meta property="og:description" content="原创文章，转载请注明出处：用Python的交易员 前言 从本篇教程开始，所有的开发都会在Python环境中进行（谢天谢地可以和C++说再见了）。 通常情况下，一个交易程序的架构会由以下三个部分组成： 底层接口：负责对接行情和交易API，将数据推送到系统核心中，以及发送指令（下单、数据请求等） 中层引擎：用于整合程序中的各个组件（包括底层接口、数据库接口等等）到一个对象中，便于顶层UI调用 顶层GUI：用于显示数据和调用中层引擎暴露的主动函数，实现各项具体功能 上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构： 两边的Adapters代表的是底层接口（左边数据，右边交易） 红色圆柱形中包括的是中层引擎架构，事件驱动方面使用了Esper复杂事件处理（CEP）引擎，同时内置了一些常用的功能引擎，如期权定价引擎、外汇对冲模块、投资组合管理模块等 上方的Strategy1、2等代表的是顶层应用（算法策略、GUI界面等），通过调用中层引擎的功能来实现用户所需的业务 vn.py和AlgoTrader的比较： 这里对两个项目做一个简单的比较。 vn.py优势： 语言易用：Java语言比Python啰嗦 架构简洁 ..."/>
        <meta property="article:published_time" content="2015-05-05" />
            <meta property="article:section" content="文章" />
            <meta property="article:author" content="用Python的交易员" />


    <!-- Bootstrap -->
        <link rel="stylesheet" href="/theme/css/bootstrap.readable.min.css" type="text/css"/>
    <link href="/theme/css/font-awesome.min.css" rel="stylesheet">

    <link href="/theme/css/pygments/monokai.css" rel="stylesheet">
    <link rel="stylesheet" href="/theme/css/style.css" type="text/css"/>


        <script>
            var _hmt = _hmt || [];
            (function() {
              var hm = document.createElement("script");
              hm.src = "//hm.baidu.com/hm.js?e8c7573f82d43fa50c895a8e28c49ceb";
              var s = document.getElementsByTagName("script")[0]; 
              s.parentNode.insertBefore(hm, s);
            })();
        </script>

</head>
<body>

<div class="navbar navbar-default navbar-fixed-top" role="navigation">
	<div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a href="/" class="navbar-brand">
<img src="/images/favicon.png" width=""/> vn.py            </a>
        </div>
        <div class="collapse navbar-collapse navbar-ex1-collapse">
            <ul class="nav navbar-nav">
                         <li><a href="/pages/quickstart.html">
                             Quick Start
                          </a></li>
                         <li><a href="/pages/tutorial.html">
                             教程
                          </a></li>
                         <li><a href="/pages/blog.html">
                             日志
                          </a></li>
                         <li><a href="/pages/screenshot.html">
                             截图
                          </a></li>
                         <li><a href="/pages/community.html">
                             社区
                          </a></li>
                         <li><a href="/pages/api.html">
                             API接口
                          </a></li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
              <li><a href="/archives.html"><i class="fa fa-th-list"></i><span class="icon-label">Archives</span></a></li>
            </ul>
        </div>
        <!-- /.navbar-collapse -->
    </div>
</div> <!-- /.navbar -->
<!-- Banner -->
<style>
	#banner{
	    background-image:url("/images/banner.png");
	}
</style>

<div id="banner">
	<div class="container">
		<div class="copy">
			<h1>vn.py</h1>
				<p class="intro">Developed by traders, for traders.</p>
		</div>
	</div>
</div><!-- End Banner -->
<div class="container">
    <div class="row">
        <div class="col-sm-9">

    <section id="content">
        <article>
            <header class="page-header">
                <h1>
                    <a href="/basic-tutorial-5.html"
                       rel="bookmark"
                       title="Permalink to Python量化交易平台开发教程系列5-底层接口对接">
                        Python量化交易平台开发教程系列5-底层接口对接
                    </a>
                </h1>
            </header>
            <div class="entry-content">
                <div class="panel">
                    <div class="panel-body">
<footer class="post-info">
    <span class="label label-default">Date</span>
    <span class="published">
        <i class="fa fa-calendar"></i><time datetime="2015-05-05T14:46:00+08:00"> 2015-05-05(周二)</time>
    </span>



    
</footer><!-- /.post-info -->                    </div>
                </div>
                <p>原创文章，转载请注明出处：用Python的交易员</p>
<h2>前言</h2>
<p>从本篇教程开始，所有的开发都会在Python环境中进行（谢天谢地可以和C++说再见了）。</p>
<p><strong>通常情况下，一个交易程序的架构会由以下三个部分组成：</strong></p>
<ul>
<li>
<p>底层接口：负责对接行情和交易API，将数据推送到系统核心中，以及发送指令（下单、数据请求等）</p>
</li>
<li>
<p>中层引擎：用于整合程序中的各个组件（包括底层接口、数据库接口等等）到一个对象中，便于顶层UI调用</p>
</li>
<li>
<p>顶层GUI：用于显示数据和调用中层引擎暴露的主动函数，实现各项具体功能</p>
</li>
</ul>
<p><img alt="AlgoTrader架构" src="http://7x2w1m.com1.z0.glb.clouddn.com/%E6%95%99%E7%A8%8B5algotrader_%E6%9E%84%E6%9E%B6.png" /></p>
<p><strong>上面这张图展示的是国外的一款开源交易平台AlgoTrader的架构：</strong></p>
<ul>
<li>
<p>两边的Adapters代表的是底层接口（左边数据，右边交易）</p>
</li>
<li>
<p>红色圆柱形中包括的是中层引擎架构，事件驱动方面使用了Esper复杂事件处理（CEP）引擎，同时内置了一些常用的功能引擎，如期权定价引擎、外汇对冲模块、投资组合管理模块等</p>
</li>
<li>
<p>上方的Strategy1、2等代表的是顶层应用（算法策略、GUI界面等），通过调用中层引擎的功能来实现用户所需的业务</p>
</li>
</ul>
<p><strong>vn.py和AlgoTrader的比较：</strong></p>
<p>这里对两个项目做一个简单的比较。</p>
<p>vn.py优势：</p>
<ul>
<li>
<p>语言易用：Java语言比Python啰嗦</p>
</li>
<li>
<p>架构简洁：Java的编程理念（纯面向对象，大量使用框架等）更是比Python的编程理念（人生苦短，我们的目标是搞定问题）繁琐</p>
</li>
<li>
<p>事件驱动引擎：AlgoTrader使用的Esper引擎尽管功能强大，使用起来也过于复杂，对于国内绝大部分的量化业务而言完全用不着</p>
</li>
<li>
<p>本地化：vn.py完全为中国市场设计，在功能设计上更符合国人的使用习惯，而AlgoTrader则是针对欧美市场设计</p>
</li>
</ul>
<p>AlgoTrader优势：</p>
<ul>
<li>
<p>静态语言：Java在开发时可以进行静态检查，同时相对较低的灵活性使得其更适合大型团队使用（即每个成员未必对项目整体非常了解）</p>
</li>
<li>
<p>国外接口：已有大量的国外经纪商和行情提供商接口，如果用户主要做欧美市场基本可以开箱即用</p>
</li>
<li>
<p>成熟度：AlgoTrader从2009发布至今已经有6年的历史，同时有着相当数量的机构客户</p>
</li>
</ul>
<p>两个项目的相似之处：</p>
<ul>
<li>
<p>作者在最初都是为了交易某种期权策略而开发了该项目</p>
</li>
<li>
<p>整体框架设计类似（底层接口、中层引擎、顶层GUI）</p>
</li>
<li>
<p>都可以非常方便的开发全自动交易策略</p>
</li>
<li>
<p>都是开源项目，目前托管在Github上（废话），用户可以根据自己的需求随意定制相关功能</p>
</li>
<li>
<p>都可以应用于高频交易（毫秒级延迟），不适用于超高频交易（微秒级延迟）</p>
</li>
</ul>
<p><strong>教程说明</strong></p>
<p>本篇教程将会介绍底层接口的开发，后面的若干篇则是关于中层引擎和各种顶层GUI组件。</p>
<p>相关的示例都是基于vn.demo中的LTS接口DEMO，发布在：
<a href="https://github.com/vnpy/vnpy/tree/master/vn.demo/ltsdemo">https://github.com/vnpy/vnpy/tree/master/vn.demo/ltsdemo</a></p>
<h2>底层接口对接</h2>
<p>通过前面的教程，我们已经获得了和原生C++ API功能完全相同的Python封装API。通常情况下，为了将某个API对接到我们的程序中，需要以下两步：</p>
<ol>
<li>
<p>将API的回调函数收到的数据推送到程序的中层引擎中，等待处理</p>
</li>
<li>
<p>将API的主动函数进行一定的简化封装，便于中层引擎调用</p>
</li>
</ol>
<p>vn.lts中的API接口在使用时需要由用户继承后实现回调函数对应的具体功能，下面的内容以行情接口为例。</p>
<h3>接口对象设计</h3>
<div class="highlight"><pre><span></span><span class="c1">########################################################################</span>
<span class="k">class</span> <span class="nc">DemoMdApi</span><span class="p">(</span><span class="n">MdApi</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Demo中的行情API封装</span>
<span class="sd">    封装后所有数据自动推送到事件驱动引擎中，由其负责推送到各个监听该事件的回调函数上</span>

<span class="sd">    对用户暴露的主动函数包括:</span>
<span class="sd">    登陆 login</span>
<span class="sd">    订阅合约 subscribe</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="c1">#----------------------------------------------------------------------</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">eventEngine</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        API对象的初始化函数</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">DemoMdApi</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">()</span>

        <span class="c1"># 事件引擎，所有数据都推送到其中，再由事件引擎进行分发</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span> <span class="o">=</span> <span class="n">eventEngine</span>

        <span class="c1"># 请求编号，由api负责管理</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="c1"># 以下变量用于实现连接和重连后的自动登陆</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__password</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>

        <span class="c1"># 以下集合用于重连后自动订阅之前已订阅的合约，使用集合为了防止重复</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># 初始化.con文件的保存目录为\mdconnection，注意这个目录必须已存在，否则会报错</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">createFtdcMdApi</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\\</span><span class="s1">mdconnection</span><span class="se">\\</span><span class="s1">&#39;</span><span class="p">)</span>
</pre></div>


<ol>
<li>
<p>DemoMdApi类继承自MdApi类，并实现了回调函数的具体功能。</p>
</li>
<li>
<p>创建DemoMdApi的对象时，用户需要传入的参数是事件驱动引擎对象eventEngine。</p>
</li>
<li>
<p>每次调用API的主动函数时，需要传入一个reqid的参数，作为本次请求的唯一标识，绝大部分情况下我们不需要在意每个请求的标识情况，因此选择将该参数交给DemoMdApi对象来维护，每次调用主动函数时自动加1。</p>
</li>
<li>
<p>我们在DemoMdApi的对象中保存用户名、密码和经纪商编号，用于前置机连接完成后的自动登录功能，以及断线重连相关的操作。</p>
</li>
<li>
<p>__setSubscribed对应的是一个Python集合，用于保存我们通过订阅函数订阅过的合约，在断线重连后自动进行订阅，之所以选择set而不是list是为了保证合约的唯一性，避免重复订阅（尽管重复订阅也没影响）。</p>
</li>
<li>
<p>在创建对象DemoMdApi对象的同时，自动调用createFtdcMdApi来初始化连接接口，选择使用当前目录下的mdconnection文件夹来保存.con通讯文件。</p>
</li>
</ol>
<h3>回调函数</h3>
<div class="highlight"><pre><span></span>    <span class="c1">#----------------------------------------------------------------------</span>
    <span class="k">def</span> <span class="nf">onFrontConnected</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;服务器连接&quot;&quot;&quot;</span>
        <span class="n">event</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_LOG</span><span class="p">)</span>
        <span class="n">event</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">&#39;log&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">u&#39;行情服务器连接成功&#39;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>

        <span class="c1"># 如果用户已经填入了用户名等等，则自动尝试连接</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span><span class="p">:</span>
            <span class="n">req</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="n">req</span><span class="p">[</span><span class="s1">&#39;UserID&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span>
            <span class="n">req</span><span class="p">[</span><span class="s1">&#39;Password&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__password</span>
            <span class="n">req</span><span class="p">[</span><span class="s1">&#39;BrokerID&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span> <span class="o">+</span> <span class="mi">1</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">reqUserLogin</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__reqid</span><span class="p">)</span>

<span class="o">...</span>

    <span class="c1">#----------------------------------------------------------------------</span>
    <span class="k">def</span> <span class="nf">onRspUserLogin</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">error</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">last</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;登陆回报&quot;&quot;&quot;</span>
        <span class="n">event</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_LOG</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">error</span><span class="p">[</span><span class="s1">&#39;ErrorID&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">log</span> <span class="o">=</span> <span class="s1">u&#39;行情服务器登陆成功&#39;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">log</span> <span class="o">=</span> <span class="s1">u&#39;登陆回报，错误代码：&#39;</span> <span class="o">+</span> <span class="nb">unicode</span><span class="p">(</span><span class="n">error</span><span class="p">[</span><span class="s1">&#39;ErrorID&#39;</span><span class="p">])</span> <span class="o">+</span> <span class="s1">u&#39;,&#39;</span> <span class="o">+</span> <span class="s1">u&#39;错误信息：&#39;</span> <span class="o">+</span> <span class="n">error</span><span class="p">[</span><span class="s1">&#39;ErrorMsg&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;gbk&#39;</span><span class="p">)</span>

        <span class="n">event</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">&#39;log&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">log</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>

        <span class="c1"># 重连后自动订阅之前已经订阅过的合约</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">instrument</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="n">instrument</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">instrument</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

<span class="o">...</span>

    <span class="c1">#----------------------------------------------------------------------  </span>
    <span class="k">def</span> <span class="nf">onRtnDepthMarketData</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;行情推送&quot;&quot;&quot;</span>
        <span class="c1"># 行情推送收到后，同时触发常规行情事件，以及特定合约行情事件，用于满足不同类型的监听</span>

        <span class="c1"># 常规行情事件</span>
        <span class="n">event1</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="n">EVENT_MARKETDATA</span><span class="p">)</span>
        <span class="n">event1</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event1</span><span class="p">)</span>

        <span class="c1"># 特定合约行情事件</span>
        <span class="n">event2</span> <span class="o">=</span> <span class="n">Event</span><span class="p">(</span><span class="n">type_</span><span class="o">=</span><span class="p">(</span><span class="n">EVENT_MARKETDATA_CONTRACT</span><span class="o">+</span><span class="n">data</span><span class="p">[</span><span class="s1">&#39;InstrumentID&#39;</span><span class="p">]))</span>
        <span class="n">event2</span><span class="o">.</span><span class="n">dict_</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__eventEngine</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">event2</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>


<ol>
<li>
<p>通过回调函数收到API的数据推送后，创建不同类型的事件Event对象（来自于事件驱动引擎模块），在事件对象的数据字典dict_中保存需要具体推送的数据，然后推送到事件驱动引擎中，由其负责处理。</p>
</li>
<li>
<p>回调函数收到的数据中，data和error分别对应的是保存主要数据（如行情）和错误信息的字典，n是该回调函数对应的请求号（即调用主动函数时的reqid），last是一个布尔值，代表是否为该次调用的最后返回信息。</p>
</li>
<li>
<p>我们主要对data字典感兴趣，因此选择在事件中整体推送。</p>
</li>
<li>
<p>而error字典每次收到后应当立即检查是否包含错误信息（因为即使没有发生错误也会推送），若有则自动保存为一个日志事件（通过日志监控控件显示出来）。</p>
</li>
<li>
<p>服务器连接完成后（onFrontConnected），检查是否已经填入了用户名等登录信息，若有则自动登录（请参考后面主动函数中的示例）。</p>
</li>
<li>
<p>登陆完成后（onRspUserLogin），自动订阅__setSubscribed中之前已经订阅过的合约。</p>
</li>
<li>
<p>收到行情推送后（onRtnDepthMarketData），我们选择创建两种事件，一种是常规行情事件（通常适用于市场行情监控GUI等对所有行情推送都关注的组件），另一种是特定合约行情事件（通常适用于算法等仅关注特定合约行情的组件）。</p>
</li>
<li>
<p>当我们调用会有返回信息的主动函数时，需要传入本次请求的编号，此时我们先将__reqid自加1，再作为参数传入主动函数中。</p>
</li>
</ol>
<h3>主动函数</h3>
<div class="highlight"><pre><span></span>    <span class="c1">#----------------------------------------------------------------------</span>
    <span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">brokerid</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;连接服务器&quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__userid</span> <span class="o">=</span> <span class="n">userid</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__password</span> <span class="o">=</span> <span class="n">password</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__brokerid</span> <span class="o">=</span> <span class="n">brokerid</span>

        <span class="c1"># 注册服务器地址</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">registerFront</span><span class="p">(</span><span class="n">address</span><span class="p">)</span>

        <span class="c1"># 初始化连接，成功会调用onFrontConnected</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">()</span>

    <span class="c1">#----------------------------------------------------------------------</span>
    <span class="k">def</span> <span class="nf">subscribe</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">instrumentid</span><span class="p">,</span> <span class="n">exchangeid</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;订阅合约&quot;&quot;&quot;</span>
        <span class="n">req</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="n">req</span><span class="p">[</span><span class="s1">&#39;InstrumentID&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">instrumentid</span>
        <span class="n">req</span><span class="p">[</span><span class="s1">&#39;ExchangeID&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">exchangeid</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">subscribeMarketData</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>

        <span class="n">instrument</span> <span class="o">=</span> <span class="p">(</span><span class="n">instrumentid</span><span class="p">,</span> <span class="n">exchangeid</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__setSubscribed</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">instrument</span><span class="p">)</span>
</pre></div>


<ol>
<li>
<p>主动函数仅封装了两个功能，登录login和订阅合约subscribe。这里假设通常我们不会做登出（直接杀进程）和退订合约（不一定）之类的操作，有需求的话可以自行封装对应的函数。</p>
</li>
<li>
<p>对于登录函数login而言，传入参数包括服务器前置机地址address，用户名userid，密码password以及经纪商代码brokerid。函数调用后，我们先将userid，password和brokerid保存下来，然后注册服务器地址registerFront，并初始化连接init。连接完成后，onFrontConnected回调函数会被自动调用，然后发生的操作请参考前一段落的回调函数工作流程。</p>
</li>
<li>
<p>LTS的API在订阅行情时，需要传入合约的代码以及合约所在的交易所（因为存在两个证券交易所相同代码的情况），而CTP的API在期货方面则不存在该问题，只需传入合约代码。发送订阅请求后，将该订阅请求保存在__setSubscribed集合中，使得断线重连时可以自动重新订阅。</p>
</li>
</ol>
<h2>总结</h2>
<p>在交易程序的开发中，所有的API对接原理均大同小异，除了类CTP API以外，国内的恒生接口、FIX引擎接口等等也可以同样遵照以上的原理进行对接设计。</p>
<p>文章中的例子是行情接口，交易接口因为包含了更多的回调函数和主动函数，在设计上相对更为复杂，感兴趣读者建议直接阅读demo中的源代码，相关问题可以在vn.py框架交流群（群号：262656087）中提问。</p>
            </div>
            <!-- /.entry-content -->
        </article>
    </section>

        </div>
        <div class="col-sm-3" id="sidebar">
            <aside>

<section class="well well-sm">
    <ul class="list-group list-group-flush">
            <li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Social</span></h4>
              <ul class="list-group" id="social">
                <li class="list-group-item"><a href="http://github.com/vnpy/vnpy"><i class="fa fa-github-square fa-lg"></i> Github</a></li>
              </ul>
            </li>



    <li class="list-group-item"><h4><i class="fa fa-external-link-square fa-lg"></i><span class="icon-label">Links</span></h4>
      <ul class="list-group" id="links">
        <li class="list-group-item">
            <a href="http://www.vnpie.com" target="_blank">
                官方论坛 - 维恩的派
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.trader" target="_blank">
                交易平台
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.event" target="_blank">
                事件引擎
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.ctp" target="_blank">
                CTP接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.xspeed" target="_blank">
                飞创接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.femas" target="_blank">
                飞马接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="https://github.com/vnpy/vnpy/tree/master/vn.lts" target="_blank">
                LTS接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.ksotp" target="_blank">
                金仕达期权接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.ksgold" target="_blank">
                金仕达黄金接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.sgit" target="_blank">
                飞鼠接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/dev/vn.qdp" target="_blank">
                QDP接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.oanda" target="_blank">
                OANDA接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.ib" target="_blank">
                IB接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.shzd" target="_blank">
                直达期货接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.okcoin" target="_blank">
                OKCoin接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.datayes" target="_blank">
                通联数据接口
            </a>
        </li>
        <li class="list-group-item">
            <a href="http://github.com/vnpy/vnpy/tree/master/vn.demo" target="_blank">
                开发DEMO
            </a>
        </li>
      </ul>
    </li>
    </ul>
</section>
            </aside>
        </div>
    </div>
</div>
<footer>
   <div class="container">
      <hr>
      <div class="row">
         <div class="col-xs-10">&copy; 2017 用Python的交易员
            &middot; Powered by <a href="https://github.com/DandyDev/pelican-bootstrap3" target="_blank">pelican-bootstrap3</a>,
            <a href="http://docs.getpelican.com/" target="_blank">Pelican</a>,
            <a href="http://getbootstrap.com" target="_blank">Bootstrap</a>         </div>
         <div class="col-xs-2"><p class="pull-right"><i class="fa fa-arrow-up"></i> <a href="#">Back to top</a></p></div>
      </div>
   </div>
</footer>
<script src="/theme/js/jquery.min.js"></script>

<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/theme/js/bootstrap.min.js"></script>

<!-- Enable responsive features in IE8 with Respond.js (https://github.com/scottjehl/Respond) -->
<script src="/theme/js/respond.min.js"></script>

    <script src="/theme/js/bodypadding.js"></script>

</body>
</html>